#ifndef GLWIDGET_H
#define GLWIDGET_H

#include <QWidget>
#include <QImage>
#include <QFile>
#include <QRgb>
#include <QMatrix3x3>
#include <QMatrix4x4>
#include <QVector2D>
#include <QVector3D>
#include <QVector4D>
#include <QMouseEvent>
#include <QPair>
#include <QList>
#include <QMutex>

#include <QOpenGLWidget>
#include <QGLFormat>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLFunctions>
#include <QOpenGLShader>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>

class GLWidget:public QOpenGLWidget,protected QOpenGLFunctions_3_3_Core//protected QOpenGLFunctions
{
    Q_OBJECT
public:
    GLWidget(QWidget *parent);

    QMatrix4x4 getCameraViewMat();
    QMatrix4x4 getCameraProjectionMat();
    QMatrix4x4 getCameraScaleTransMat();        //平移缩放矩阵

    void setVolume8UC1Data(unsigned char *data,int width,int height,int count); //由调用者删除指针内存

    void resetVoxelRGBSegmentPoints();
    void addVoxelRGBSegment( double x1, double r1, double g1, double b1,
                             double x2, double r2, double g2, double b2 );
    void clearVoxelRGBSegmentPoints();
    void modifiedVoxelColorFunc();

    ~GLWidget();

public slots:
    void resetCamera();
    void resetCameraToXYPlane();
    void resetCameraToXZPlane();
    void resetCameraToYZPlane();

    void setCameraOrtho(bool y=true);
    void setCameraMoveMode(bool afterProjection=true);
    void setCameraScaleMode(bool scaleCenter=true);

    void setVolumeOpacity(double opacity);
    void setVolumeBrightness(double brightness);
    void setVolumeThreshold(double threshold);
    void setVolumeGradient(double gradient);

    void testSurfaceVisible(bool visible = false);

    void on_btnGetDepthBufTest1Clicked();
    void on_btnVolumeTestClicked();

    // QWidget interface
protected:
    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void wheelEvent(QWheelEvent *event);

    // QOpenGLWidget interface
protected:
    void initializeGL();
    void resizeGL(int w, int h);
    void paintGL();

private:
    typedef struct{
        GLuint program;
        const GLint vertArrayLoc = 0;
        const GLint colorArrayLoc = 1;
        GLint projViewMat4loc;
    } GLCommonProgram;

    typedef struct {
        GLuint vao;
        GLuint vbo;
        GLuint ebo;
        QMatrix4x4 modelMat;    //转换为世界坐标矩阵
        GLuint texture1;
        QString vertexCodeFile;
        QString fragmentCodeFile;
        GLuint program;
        GLint colorloc;
        GLint projViewMat4loc;
        bool visible = false;
    } GLFaceObjContext;

    typedef struct {
        GLuint program;

        GLuint vao;
        GLuint vbo;
        GLuint ebo;

        // 用于绘制整个屏幕
        // 由于使用了3.x core profile所以必须使用vao(单独vbo不行 直接设置数据指针也不行)，
        // 而compatibility profile 默认就有个全局vao 0
        // compatibility profile 的 glBindVertexArray(0) 相当于使用了默认的vao 0
        GLuint vao_fill;
        GLuint vbo_fill;       // 用于绘制整个屏幕

        QMatrix4x4 modelMat;    //体绘制转换为世界坐标矩阵
        QVector3D dataXYZ;      //原始体数据的尺寸 Y对应帧数 Z对应图像高度
        float opacity = 0.05f;      //不透明度
        float brightness = 5.0f;   //亮度
        float alphaThreshold = 1.0f/255.0f;   // 不透明度阈值
        float alphaGradient = 0.0f; //不透明度梯度比例

        GLuint bgDepthTex;  //背景深度纹理
        GLuint fbo;         //体绘制计算帧缓冲
        GLuint rbo;         //体绘制计算帧缓冲的渲染缓冲附件
        GLuint colortex;    //体绘制计算帧缓冲的颜色附件
        GLuint depthtex;    //体绘制计算帧缓冲的深度附件

        GLuint bgColorTex;   //体绘制之前的背景颜色缓冲

        GLuint objbottomTex;   //体绘制对象的底面坐标纹理

        GLuint colormap1dTex;  //灰度映射为彩色的一维纹理
        GLuint obj3d8UC1Tex;    //体绘制三维体数据8位无符号单通道纹理

        //着色器 uniform 位置
        GLint projViewMat4loc = -1;    //透视视图矩阵位置
        GLint projMatrixLoc = -1;      //投影变换矩阵位置
        GLint renderSteploc = -1;   //渲染步骤位置
        GLint volumeXYZloc = -1;       //体数据世界坐标的长宽高位置
        GLint viewportWHloc = -1;       //渲染的视口宽高位置
        GLint opacityLoc = -1;      //不透明度位置
        GLint brightnessLoc = -1;   //亮度位置
        GLint alphaThresholdLoc = -1;   // 不透明度阈值位置
        GLint alphaGradientLoc = -1; //不透明度梯度比例位置

        GLint bottomTexUnit = -1;    //底面坐标纹理对应单元
        GLint volumeDataTexUnit = -1;    //三维体数据纹理对应单元
        GLint colormap1dTexUnit = -1;    //灰度映射为彩色的一维纹理对应单元
        GLint bgColorTexUnit = -1;      //  背景颜色纹理对应单元
        GLint bgDepthTexUnit = -1;      //  背景深度纹理对应单元深度
    } GLVolumeObjContext;

    typedef struct{
        QVector3D pos;  //相机位置
        QVector3D dst;  //目标位置
        QVector3D headV;  //相机顶指向方向向量 (0,1,0)

        bool isOrthoMode = true;    //是否正交投影

        bool moveAfterProjection = true;   //是否平移为在投影矩阵之后
        bool scaleByCenter = true; //是否以可视中心为参考缩放图像

        int resetTo = 0;    //复位到哪个面   0: XY  1: XZ  2: YZ

        //透视投影用的参数
        float verticalAngle = 90.0f;     //垂直可视开角
        float aspectRatio = 1.0f;       //可视平面宽高比

        //正交投影用的参数
        float leftPlane = -1.0f;      //正交可视左面
        float rightPlane = 1.0f;     //正交可视右面
        float bottomPlane = -1.0f;    //正交可视底面
        float topPlane = 1.0f;      //正交可视顶面

        //通用投影用的参数
        float nearPlane = 0.0f;         //透视投影可视近平面 或 正交投影可视近平面
        float farPlane = 2.0f;          //透视投影可视远平面 或 正交投影可视近平面

        //旋转参数 单位-角度
        QMatrix4x4 rotateMat;

        //移动参数
        QVector3D trans;    //移动向量

        //缩放
        float zoom = 1.0f;
        float basezoom = 1.0f;

    } CameraSZ;

    typedef struct{
        float left=-1.0f;
        float right=1.0f;
        float bottom=-1.0f;
        float top=1.0f;
        float front=1.0f;
        float back=-1.0f;
    }CubeBoundarySZ;

    typedef enum{
        CAMCT_NONE,
        CAMCT_PITCH_YAW,
        CAMCT_PITCH,
        CAMCT_YAW,
        CAMCT_ROLL,
        CAMCT_ZOOM,
        CAMCT_MOVE,
    }CameraControlTool;

    typedef struct{
        double r;
        double g;
        double b;
    }DoubleRGBSZ;

//    QOpenGLShaderProgram m_shaderProgram;

//    GLuint m_triangleVBO, m_triangleVAO, m_triangleEBO;

//    QOpenGLBuffer m_triangleVBO, m_triangleEBO;
//    QOpenGLVertexArrayObject m_triangleVAO;

    QMutex m_paintingMutex;

    CameraSZ m_camera,m_camera_;
    QMatrix4x4 m_lastCameraMat;
    bool m_isCamera1stReseted;

    QRectF m_glviewport;
    bool m_isViewportChanged; //当前视口是否变动了
    int m_viewportWidth;
    int m_viewportHeight;

    CubeBoundarySZ m_mainObjBoundary;

    CameraControlTool m_cameraTool;

    QPoint m_lastMousePos;

    GLCommonProgram m_glCommonProgram;

    GLFaceObjContext m_triangleCtx;

    GLVolumeObjContext m_volumeCtx;

    QList<QPair<double,DoubleRGBSZ>> m_colorfuncRGBPoints;
    bool m_colorFuncChanged;
    float *m_pColorFuncTexBuf;

    float getMainObjMaxSize();
    QVector3D getMainObjCenter();
    float getMainObjWidth();
    float getMainObjHeight();
    float getMainObjDepth();

    void learnTestProjectionMatrix();
    void initGLCommonProgrom();
    void initGLTriangle();
    void initGLVolume();
    bool reallocateVolumeTexture();
    void paintGLTest();
    void paintGLTriangle();
    void paintGLVolume();
};

#endif // GLWIDGET_H
